package com.beiding.isolateloader;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

//指挥官类加载器
public class CommanderClassLoader extends ClassLoader {

    //公共类加载器
    private ClassLoader commonClassLoader;

    //被缓存的公共类的map
    private Map<String, Class> cacheCommonClassMap = new HashMap<>();

    //公共类加载器中没有
    private Set<String> passCommon = new HashSet<>();

    private static final Method load;

    static {
        try {
            load = ClassLoader.class.getDeclaredMethod("loadClass", String.class, boolean.class);
            load.setAccessible(true);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public Class findFromCommon(String name) {
        if (passCommon.contains(name)) {
            return null;
        }
        Class aClass = cacheCommonClassMap.get(name);
        if (aClass != null) {
            return aClass;
        }

        try {
            aClass = commonClassLoader.loadClass(name);
            cacheCommonClassMap.put(name, aClass);
            return aClass;
        } catch (Exception ignore) {
            passCommon.add(name);
            return null;
        }
    }

    public Class findFromCommon(String name, boolean resolve) {
        if (passCommon.contains(name)) {
            return null;
        }
        Class aClass = cacheCommonClassMap.get(name);
        if (aClass != null) {
            return aClass;
        }
        try {
            aClass = (Class) load.invoke(commonClassLoader, name, resolve);
            cacheCommonClassMap.put(name, aClass);
            return aClass;
        } catch (Exception ignore) {
            passCommon.add(name);
            return null;
        }
    }

    @Override
    public Class<?> loadClass(String name) throws ClassNotFoundException {
        Class fromCommon = findFromCommon(name);
        if (fromCommon != null) {
            return fromCommon;
        }
        return super.loadClass(name);
    }

    @Override
    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
        Class fromCommon = findFromCommon(name, resolve);
        if (fromCommon != null) {
            return fromCommon;
        }
        return super.loadClass(name, resolve);
    }
}
